#include<iostream>
#include<vector>
#include<string>
#include<boost/filesystem.hpp>
#include"util.hpp"

const std::string src_path ="data/input";
const std::string output="data/raw_html/raw.txt";

typedef struct DocInfo
{
  std::string title;   //文档的标题
  std::string content; //文档内容
  std::string url;     //该文档在官网中的url
}DocInfo_t;

// const & 输入参数
// * 输出型参数
// & 输入输出型参数

bool EnumFile(const std::string& src_path,std::vector<std::string>* file_list);
bool ParserHtml(const std::vector<std::string>& file_list,std::vector<DocInfo_t>* results);
bool SaveHtml(const std::vector<DocInfo_t>& results,const std::string& output);

int main()
{
  //第一步，递归式的把每一个html文件带路径，保存到file_list中
  std::vector<std::string> file_list;
  if(!EnumFile(src_path,&file_list))//该函数是判断是否成功完成第一步
  {                        //file_list是一个输出型参数(把函数内部的数据传输到函数外部),所以要传地址
    std::cerr<<"enum file name error"<<std::endl;
    return 1;
  }

  //第二步：按照file_list读取每一个文件的内容，并进行解析
  std::vector<DocInfo_t> results;
  if(!ParserHtml(file_list,&results))
  {
    std::cerr<<"parser html error"<<std::endl;
    return 2;
  }

  //第三步：把解析完毕的各个内容，写入到指定的文档中（路径为output)，以/3为分隔符
  if(!SaveHtml(results,output))
  {
   std::cerr<<"save html error"<<std::endl;
   return 3;
  }

  return 0;

}


bool EnumFile(const std::string& src_path,std::vector<std::string>* file_list)
{
  namespace fs=boost::filesystem;
  fs::path root_path(src_path);
  if(!fs::exists(root_path))
  {
    std::cerr<<src_path<<"not exits"<<std::endl;
    return false;
  }

  //定义一个空的迭代器来进行循环结束的判断
  fs::recursive_directory_iterator end;
  for(fs::recursive_directory_iterator iter(root_path);iter!=end;++iter)
  {
     //判断是否为普通文件，像目录文件是不需要的
     if(!fs::is_regular_file(*iter))
     {
       continue;
     }
     //判断是否以.html结尾
     if(iter->path().extension()!=".html")
     {
        continue;
     }
     // 能走到这里说明这是一个html文件
   //  std::cout<<"debug"<<iter->path().string()<<std::endl;
     file_list->push_back(iter->path().string());
     
  }
  return true;
}

static bool ParserTitle(const std::string& file,std::string* title)
{
  std::size_t begin=file.find("<title>");
  if(begin==std::string::npos)
  {
    return false;
  }

  std::size_t end=file.find("</title>");
  if(end==std::string::npos)
  {
    return false;
  }
  begin=begin+std::string("<title>").size();
  if(begin>end)
    return false;
  *title=file.substr(begin,end-begin);
  return true;
}

static bool ParserContent(const std::string& file ,std::string* content )
{
  //去标签，基于一个简易的状态机,什么是状态机
  enum status
  {
    LABLE,
    CONTENT
  };
  enum status s=LABLE;
  for(char c:file)
  {
    switch(s)
    {
      case LABLE:
        if(c=='>') s=CONTENT; //如果c=='>',说明已经处理完一个标签
        break;
      case CONTENT:
        if(c=='<') s=LABLE;  //如果c=='>',说明有开始遇到了一个标签
        else 
        {
          //我们不想保留原始文件中的\n，因为我们想用\n作为html解析之后的风格符
          if(c!='\n')
           content->push_back(c);
        }
        break;
      default:
        break;
    }
  }
   return true;
}

static bool ParserUrl(const std::string& file_path,std::string* url)
{
  std::string url_head="https://www.boost.org/doc/libs/1_78_0/doc/html";
  std::string url_tail=file_path.substr(src_path.size());
 // std::cout<<"file_path "<<file_path<<std::endl;
 // std::cout<<"url_path"<<url_tail<<std::endl;
  *url=url_head+url_tail;
  return true;
}

//for debug
//void ShowDoc(const DocInfo_t& doc)
//{
 // std::cout<<"title "<<doc.title<<std::endl;
 // std::cout<<"content "<<doc.content<<std::endl;
 // std::cout<<"url "<<doc.url<<std::endl;
//}

bool ParserHtml(const std::vector<std::string>& file_list,std::vector<DocInfo_t>* results)
{
 for(const std::string& file:file_list)
 {
   // 1.读取文件，ReadFile();
  std::string result;    //存放读取到的文件
  if(!ns_util::FileUtil::ReadFile(file,&result))
  {
    continue;
  }
  DocInfo_t doc;
   // 2.解析指定的文件，提取title
  if(!ParserTitle(result,&doc.title))
  {
    continue;
  }
   // 3.解析指定的文件，提取content
  if(!ParserContent(result,&doc.content))
  {
    continue;
  }
   // 4.解析指定的文件，构建URL
  if(!ParserUrl(file,&doc.url))
  {
    continue;
  }
  //走到这里，当前路劲所指向的.html文档中的相关内容已经都存在了doc中
  results->push_back(std::move(doc));//细节，本质会发生拷贝，效率可能比较低
                          //用move函数能够减少拷贝，提高效率
  //for debug
  //ShowDoc(doc);
  //break;
 }
  return true;
}

bool SaveHtml(const std::vector<DocInfo_t>& results,const std::string& output)
{
#define SEP '\3'
  //按照二进制的方式写入
  std::ofstream out(output,std::ios::out | std::ios::binary);
  if(!out.is_open())
  {
    std::cerr<<"open "<<output<<" fail"<<std::endl;
    return false;
  }

  for(auto& item:results)
  {
    std::string out_string;
    out_string+=item.title;
    out_string += SEP;
    out_string+=item.content;
    out_string += SEP;
    out_string+=item.url;
  //  out_string += SEP;
  //  out_string+=item.url;

    out_string += '\n';

    out.write(out_string.c_str(),out_string.size());
  }
  out.close();
  return true;
}















